package org.herrdommel.preference;

import java.util.Arrays;
import java.util.List;

import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.preference.ListPreference;
import android.util.AttributeSet;
import android.widget.ListView;

public class MultiSelectListPreference extends ListPreference {
	private final String SEPARATOR = "|";
	private final String CHECK_ALL_KEY = "#ALL#";
	private final boolean[] selectedEntryIndices;

	public MultiSelectListPreference(final Context context, final AttributeSet attrs) {
		super(context, attrs);
		selectedEntryIndices = new boolean[getEntries().length];
	}

	public MultiSelectListPreference(final Context context) {
		this(context, null);
	}

	@Override
	protected void onPrepareDialogBuilder(final Builder builder) {
		final CharSequence[] entries = getEntries();
		final CharSequence[] entryValues = getEntryValues();
		if (entries == null || entryValues == null || entries.length != entryValues.length) {
			throw new IllegalStateException("entries.length != entryValues.length");
		}

		restoreCheckedEntries();
		builder.setMultiChoiceItems(entries, selectedEntryIndices, new DialogInterface.OnMultiChoiceClickListener() {
			@Override
			public void onClick(final DialogInterface dialog, final int position, final boolean value) {
				if (getEntryValues()[position].equals(CHECK_ALL_KEY)) {
					checkAll(dialog, value);
				} else {
					checkOne(dialog, position, value);
				}
			}
		});
	}

	@Override
	protected void onDialogClosed(final boolean positiveResult) {
		if (positiveResult) {
			final CharSequence[] entryValues = getEntryValues();
			final StringBuilder sb = new StringBuilder();
			for (int i = 1; i < entryValues.length; i++) {
				if (selectedEntryIndices[i] == true) {
					sb.append(entryValues[i] + SEPARATOR);
				}
			}
			if (sb.length() > 0) {
				sb.deleteCharAt(sb.length() - 1);
			}
			final String persistString = sb.toString();
			persistString(persistString);
			callChangeListener(persistString);
		}
	}

	private void checkAll(final DialogInterface dialog, final boolean val) {
		final ListView lv = ((AlertDialog) dialog).getListView();
		final int size = lv.getCount();
		for (int i = 0; i < size; i++) {
			lv.setItemChecked(i, val);
			selectedEntryIndices[i] = val;
		}
	}

	private void checkOne(final DialogInterface dialog, final int position, final boolean value) {
		final ListView lv = ((AlertDialog) dialog).getListView();
		lv.setItemChecked(position, value);
		selectedEntryIndices[position] = value;
		boolean allChecked = true;
		for (int i = 1; i < selectedEntryIndices.length; i++) {
			if (!selectedEntryIndices[i]) {
				allChecked = false;
				break;
			}
		}
		lv.setItemChecked(0, allChecked);
		selectedEntryIndices[0] = allChecked;
	}

	private void restoreCheckedEntries() {
		final CharSequence[] entryValues = getEntryValues();
		final String[] vals = parseStoredValue(getPersistedString(null));

		if (vals != null) {
			final List<String> valuesList = Arrays.asList(vals);
			if (valuesList.size() == entryValues.length) {
				selectedEntryIndices[0] = true;
			} else {
				selectedEntryIndices[0] = false;
			}
			for (int i = 1; i < entryValues.length; i++) {
				final CharSequence entry = entryValues[i];
				if (valuesList.contains(entry)) {
					selectedEntryIndices[i] = true;
				} else {
					selectedEntryIndices[i] = false;
				}
			}
		}
	}

	private String[] parseStoredValue(final CharSequence value) {
		if (value != null && !value.equals("")) {
			return ((String) value).split("\\" + SEPARATOR);
		}
		return null;
	}

}
